﻿/* Copyright (C) 2007-2010 STS Soft

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;
#if !WindowsCE && !PocketPC
using System.Runtime.Serialization.Formatters.Binary;
#endif

namespace STSdb.General.Streams
{
    public static class PrimitiveSerialization
    {
        //public static object ReadObject(this BinaryReader reader)
        //{
        //    TypeID typeID = (TypeID)reader.ReadByte();

        //    switch (typeID)
        //    {
        //        case TypeID.Null:
        //            return null;

        //        case TypeID.String:
        //            return reader.ReadString();

        //        case TypeID.Int32:
        //            return reader.ReadInt32();

        //        case TypeID.Boolean:
        //            return reader.ReadBoolean();

        //        case TypeID.DateTime:
        //            return new DateTime(reader.ReadInt64());

        //        case TypeID.Decimal:
        //            return reader.ReadDecimal();

        //        case TypeID.Byte:
        //            return reader.ReadByte();

        //        case TypeID.Char:
        //            return reader.ReadChar();

        //        case TypeID.Single:
        //            return reader.ReadSingle();

        //        case TypeID.Double:
        //            return reader.ReadDouble();

        //        case TypeID.SByte:
        //            return reader.ReadSByte();

        //        case TypeID.Int16:
        //            return reader.ReadInt16();

        //        case TypeID.Int64:
        //            return reader.ReadInt64();

        //        case TypeID.UInt16:
        //            return reader.ReadUInt16();

        //        case TypeID.UInt32:
        //            return reader.ReadUInt32();

        //        case TypeID.UInt64:
        //            return reader.ReadUInt64();

        //        case TypeID.TimeSpan:
        //            return new TimeSpan(reader.ReadInt64());

        //        case TypeID.Guid:
        //            return new Guid(reader.ReadBytes(0x10));

        //        case TypeID.IntPtr:
        //            {
        //                if (IntPtr.Size != 4)
        //                    return new IntPtr(reader.ReadInt64());
        //                else
        //                    return new IntPtr(reader.ReadInt32());
        //            }

        //        case TypeID.UIntPtr:
        //            {
        //                if (UIntPtr.Size != 4)
        //                    return new UIntPtr(reader.ReadUInt64());
        //                else
        //                    return new UIntPtr(reader.ReadUInt32());
        //            }

        //        case TypeID.Object:
        //            return ReadAsOjbect(reader);

        //        default:
        //            throw new NotSupportedException(typeID.ToString());
        //    }
        //}

        //public static void WriteObject(this BinaryWriter writer, object value)
        //{
        //    if (value == null)
        //    {
        //        writer.Write((byte)TypeID.Null);
        //    }
        //    else if (value is String)
        //    {
        //        writer.Write((byte)TypeID.String);
        //        writer.Write((String)value);
        //    }
        //    else if (value is Int32)
        //    {
        //        writer.Write((byte)TypeID.Int32);
        //        writer.Write((Int32)value);
        //    }
        //    else if (value is Boolean)
        //    {
        //        writer.Write((byte)TypeID.Boolean);
        //        writer.Write((Boolean)value);
        //    }
        //    else if (value is DateTime)
        //    {
        //        writer.Write((byte)TypeID.DateTime);
        //        DateTime time = (DateTime)value;
        //        writer.Write(time.Ticks);
        //    }
        //    else if (value is Decimal)
        //    {
        //        writer.Write((byte)TypeID.Decimal);
        //        writer.Write((decimal)value);
        //    }
        //    else if (value is Byte)
        //    {
        //        writer.Write((byte)TypeID.Byte);
        //        writer.Write((Byte)value);
        //    }
        //    else if (value is Char)
        //    {
        //        writer.Write((byte)TypeID.Char);
        //        writer.Write((Char)value);
        //    }
        //    else if (value is Single)
        //    {
        //        writer.Write((byte)TypeID.Single);
        //        writer.Write((Single)value);
        //    }
        //    else if (value is Double)
        //    {
        //        writer.Write((byte)TypeID.Double);
        //        writer.Write((Double)value);
        //    }
        //    else if (value is SByte)
        //    {
        //        writer.Write((byte)TypeID.SByte);
        //        writer.Write((SByte)value);
        //    }
        //    else if (value is Int16)
        //    {
        //        writer.Write((byte)TypeID.Int16);
        //        writer.Write((Int16)value);
        //    }
        //    else if (value is Int64)
        //    {
        //        writer.Write((byte)TypeID.Int64);
        //        writer.Write((Int64)value);
        //    }
        //    else if (value is UInt16)
        //    {
        //        writer.Write((byte)TypeID.UInt16);
        //        writer.Write((UInt16)value);
        //    }
        //    else if (value is UInt32)
        //    {
        //        writer.Write((byte)TypeID.UInt32);
        //        writer.Write((UInt32)value);
        //    }
        //    else if (value is UInt64)
        //    {
        //        writer.Write((byte)TypeID.UInt64);
        //        writer.Write((UInt64)value);
        //    }
        //    else if (value is TimeSpan)
        //    {
        //        writer.Write((byte)TypeID.TimeSpan);
        //        TimeSpan span = (TimeSpan)value;
        //        writer.Write(span.Ticks);
        //    }
        //    else if (value is Guid)
        //    {
        //        writer.Write((byte)TypeID.Guid);
        //        byte[] buffer = ((Guid)value).ToByteArray();
        //        writer.Write(buffer);
        //    }
        //    else if (value is IntPtr)
        //    {
        //        writer.Write((byte)TypeID.IntPtr);
        //        IntPtr ptr = (IntPtr)value;
        //        if (IntPtr.Size == 4)
        //            writer.Write(ptr.ToInt32());
        //        else
        //            writer.Write(ptr.ToInt64());
        //    }
        //    else if (value is UIntPtr)
        //    {
        //        writer.Write((byte)TypeID.UIntPtr);
        //        UIntPtr ptr2 = (UIntPtr)value;
        //        if (UIntPtr.Size == 4)
        //            writer.Write(ptr2.ToUInt32());
        //        else
        //            writer.Write(ptr2.ToUInt64());
        //    }
        //    else
        //    {
        //        writer.Write((byte)TypeID.Object);
        //        WriteAsOjbect(writer, value);
        //    }
        //}

        /// <summary>
        /// Returns not null value.
        /// </summary>
        public static object ReadAsOjbect(this BinaryReader reader)
        {
            if (reader.ReadBoolean()) //IsSerializable
            {
#if !WindowsCE && !PocketPC
                BinaryFormatter formatter = new BinaryFormatter();
                return formatter.Deserialize(reader.BaseStream);
#else
                throw new NotSupportedException();
#endif
            }
            else
            {
                string typeName = reader.ReadString();
                XmlSerializer serializer = new XmlSerializer(Type.GetType(typeName));
                return serializer.Deserialize(reader.BaseStream);
            }
        }

        /// <summary>
        /// Writes a not null value. 
        /// </summary>
        public static void WriteAsOjbect(this BinaryWriter writer, object value)
        {
            Type type = value.GetType();
#if !WindowsCE && !PocketPC
            if (type.IsSerializable)
            {
                writer.Write(true);//IsSerializable
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(writer.BaseStream, value);
            }
            else
            {
                writer.Write(false);//!IsSerializable
                XmlSerializer serializer = new XmlSerializer(type);
                writer.Write(type.FullName);
                serializer.Serialize(writer.BaseStream, value);
            }
#else
            writer.Write(false);
            XmlSerializer serializer = new XmlSerializer(type);
            writer.Write(type.AssemblyQualifiedName);
            serializer.Serialize(writer.BaseStream, value);
#endif
        }

        private enum TypeID : byte
        {
            Empty = TypeCode.Empty,         //00
            Object = TypeCode.Object,       //01
            DBNull = TypeCode.DBNull,       //02
            Boolean = TypeCode.Boolean,     //03
            Char = TypeCode.Char,           //04
            SByte = TypeCode.SByte,         //05
            Byte = TypeCode.Byte,           //06
            Int16 = TypeCode.Int16,         //07
            UInt16 = TypeCode.UInt16,       //08
            Int32 = TypeCode.Int32,         //09
            UInt32 = TypeCode.UInt32,       //10
            Int64 = TypeCode.Int64,         //11
            UInt64 = TypeCode.UInt64,       //12
            Single = TypeCode.Single,       //13
            Double = TypeCode.Double,       //14
            Decimal = TypeCode.Decimal,     //15
            DateTime = TypeCode.DateTime,   //16
            TimeSpan = 17,
            String = TypeCode.String,       //18

            Guid = 19,
            IntPtr = 20,
            Null = 21,
            UIntPtr = 22
        }
    }
}
